package mafiagame;

import java.util.ArrayList;
import java.util.List;

import mafiagame.Game.Stage;
import mafiagame.Mark.MarkScope;
import mafiagame.Mark.MarkType;
import mafiagame.Mark;
import mafiagame.Role;

public class Player
{
	// Global player data
	public String username; // Used to identify that player.
	public int id;
	Game myGame;

	enum Alignment
	{
		MAFIA, INNOCENT
	};

	public Alignment alignment;

	public String statusString;

	// List of roles
	public List<Role> roles;

	// Marks set on that player
	public List<Mark> marks;

	// Sleep phase
	public boolean sleeping;

	// Voting phase
	public int playerVote;

	public boolean living;

	public boolean gaveWill;

	// Temporary data for resolving a single situation
	List<Player> killRedirects;
	List<Player> saveRedirects;

	public void setup()
	{
		for (Role r : roles)
		{
			r.SetupPhase();
		}
	}

	public void startNight()
	{
		statusString = null;
		for (Role r : roles)
		{
			r.NightPhase();
		}
	}

	public void startDay()
	{
		for (Role r : roles)
		{
			r.DayPhase();
		}
	}

	public void endNight()
	{
		statusString = null;
		for (Role r : roles)
		{
			r.EndNightPhase();
		}
	}

	public void endDay()
	{
		for (Role r : roles)
		{
			r.EndDayPhase();
		}
	}

	public void prepareProcess()
	{
		killRedirects.clear();
		saveRedirects.clear();
		for (Mark m : marks)
		{
			m.processed = false;
			System.out.println(username + ") " + m.toString());

		}
	}

	public void processRedirectMarks()
	{
		for (Mark m : marks)
		{
			if (m.processed)
				continue;
			if (m.type == MarkType.REDIRECT_KILL)
			{
				if (!m.source.isBlocked())
				{
					killRedirects.add(m.redirectTarget);
				}
			}
			if (m.type == MarkType.REDIRECT_SAVE)
			{
				if (!m.source.isBlocked())
				{
					saveRedirects.add(m.redirectTarget);
				}
			}
			if (m.type == MarkType.GIVE_ROLE)
			{
				if (!m.source.isBlocked() && !roles.contains(m.givenRole))
				{
					roles.add(m.givenRole);
				}
			}
			if (m.type == MarkType.DELAYED_KILL)
			{
				if (!m.source.isBlocked() && m.duration == 1)
				{
					Mark n = new Mark();
					n.type = MarkType.KILL;
					n.source = GodPlayer.getGod();
					n.isBlockable = m.isBlockable;
					n.isSaveable = m.isSaveable;
					n.processed = false;
					n.duration = 1;
					n.scope = MarkScope.BOTH;
					n.isRedirectable = false;
					
					marks.add(n);
				}
			}
		}

		// Then move all redirect marks if needed
		if (killRedirects.size() > 0)
		{
			for (Mark m : marks)
			{
				if (m.type == MarkType.KILL)
				{
					for (Player p : killRedirects)
					{
						Mark n = new Mark(m);
						n.isRedirectable = false;
						p.marks.add(n);

						m.processed = true;
					}
				}
			}
		}

		if (saveRedirects.size() > 0)
		{
			for (Mark m : marks)
			{
				if (m.type == MarkType.SAVE_EXECUTION)
				{
					for (Player p : saveRedirects)
					{
						Mark n = new Mark(m);
						n.isRedirectable = false;
						p.marks.add(n);

						m.processed = true;
					}
				}
				if (m.type == MarkType.SAVE_KILL)
				{
					for (Player p : saveRedirects)
					{
						Mark n = new Mark(m);
						n.isRedirectable = false;
						p.marks.add(n);

						m.processed = true;
					}
				}
			}
		}
	}

	public void processInvestigationMarks()
	{
		for (Mark m : marks)
		{
			if (m.processed)
				continue;
			if (m.type == MarkType.INVESTIGATE_ALIGNMENT)
			{
				if (!m.isBlockable || !m.source.isBlocked())
				{
					myGame.communicator.sendPrivateMessage(m.source.username,
							this.username + " is <b>" + this.alignment);
				}
			}
			if (m.type == MarkType.INVESTIGATE_ROLE)
			{
				if (!m.isBlockable || !m.source.isBlocked())
				{
					String rolestring = "";
					for (Role r : roles)
					{
						rolestring += r.getName() + " ";
					}
					if (roles.size() > 0)
						myGame.communicator.sendPrivateMessage(
								m.source.username, this.username
										+ " has the following roles: "
										+ rolestring);
					else
						myGame.communicator.sendPrivateMessage(
								m.source.username, this.username
										+ " has no roles!");
				}
			}
		}

	}

	public void processWillMarks()
	{
		for (Mark m : marks)
		{
			if (m.processed)
				continue;
			if (m.type == MarkType.GIVE_WILL)
			{
				myGame.communicator.sendPrivateMessage(username, "Will from "
						+ m.source.username + ": " + m.willContents);
			}
		}
	}

	public void processKillMarks()
	{
		boolean isKilled = false;
		boolean isKillSaved = false;
		boolean isExecuted = false;
		boolean isExecuteSaved = false;
		for (Mark m : marks)
		{
			if (m.processed)
				continue;
			if (m.type == MarkType.KILL)
			{
				if (!m.isBlockable || !m.source.isBlocked())
					isKilled = true;
			}
			if (m.type == MarkType.SAVE_KILL)
			{
				if (!m.isBlockable || !m.source.isBlocked())
				{
					if (m.scope == MarkScope.BOTH
							|| m.scope == MarkScope.PERMANENT)
						isKillSaved = true;
					if (m.scope == MarkScope.NIGHT
							&& myGame.currentStage == Stage.NIGHT)
						isKillSaved = true;
					if (m.scope == MarkScope.DAY
							&& myGame.currentStage == Stage.DAY)
						isKillSaved = true;
				}
			}
			if (m.type == MarkType.EXECUTION)
			{
				isExecuted = true;
			}
			if (m.type == MarkType.SAVE_EXECUTION)
			{
				if (!m.isBlockable || !m.source.isBlocked())
					isExecuteSaved = true;
			}
		}

		if (isKilled)
		{
			if (isKillSaved)
			{
				myGame.savePlayer(this);
			} else
			{
				myGame.killPlayer(this);
			}
		}

		if (isExecuted)
		{
			if (isExecuteSaved)
			{
				myGame.savePlayer(this);
			} else
			{
				myGame.executePlayer(this);
			}
		}
	}

	public void processDestinyMarks()
	{
		// Dependent roles are only processed at all times
		for (Mark m : marks)
		{
			if (m.processed)
				continue;
			if (m.type == MarkType.DESTINY_BOND)
			{
				if (!m.dependentTarget.living)
				{
					Mark n = new Mark();
					n.type = MarkType.DELAYED_KILL;
					n.scope = MarkScope.BOTH;
					n.duration = 2;
					n.isBlockable = false;
					n.isSaveable = true;
					n.source = GodPlayer.getGod();
					marks.add(n);
					
					m.processed = true;
				}
			}
		}
	}

	public void postProcess()
	{
		List<Mark> keepList = new ArrayList<Mark>();
		for (Mark m : marks)
		{
			if (m.scope == MarkScope.PERMANENT)
			{
				keepList.add(m);
				continue;
			}
			if (m.scope == MarkScope.BOTH)
				m.duration--;
			if (m.scope == MarkScope.NIGHT
					&& myGame.currentStage == Stage.NIGHT)
				m.duration--;
			if (m.scope == MarkScope.DAY && myGame.currentStage == Stage.DAY)
				m.duration--;
			if (m.duration > 0)
			{
				keepList.add(m);
			} else
			{
				if (m.type == MarkType.GIVE_ROLE)
				{
					this.roles.remove(m.givenRole);
				}
			}
			System.out.println(username + ") " + m.toString());
		}
		marks.clear();
		marks.addAll(keepList);
	}

	public boolean isBlocked()
	{
		boolean isBlocked = false;
		for (Mark m : marks)
		{
			if (m.type == MarkType.BLOCK)
			{
				if (!m.source.isBlocked())
					isBlocked = true;
			}
		}
		return isBlocked;
	}

	public boolean canVote()
	{
		boolean canVote = true;
		for (Mark m : marks)
		{
			if (m.type == MarkType.REMOVE_VOTE)
			{
				if (!m.source.isBlocked())
					canVote = false;
			}
		}
		return canVote;
	}

	public Player(Game g)
	{
		statusString = null;
		myGame = g;
		marks = new ArrayList<Mark>();
		roles = new ArrayList<Role>();
		killRedirects = new ArrayList<Player>();
		saveRedirects = new ArrayList<Player>();
		gaveWill = false;
	}

	public String getMessage()
	{
		String message = "";
		message = message + "<b>" + username + "</b>";
		if (statusString != null)
		{
			message = message + " - " + statusString;
		}

		for (Role r : roles)
		{
			if (r.isPopular())
				message = message + " - " + r.getName();
		}

		return message;
	}

	public String getSpoilerMessage()
	{
		String message = "";
		message = message + "<b>" + username + "</b>";
		message = message + " - " + alignment.toString();

		for (Role r : roles)
		{
			message = message + " " + r.getName();
		}

		return message;
	}
}
